/*
 * @Date         : 2024-05-13 15:47:30 星期1
 * @Author       : xut
 * @Description  :
 */
import { resolve } from "node:path"
import grpc from "@grpc/grpc-js"
import { loadProto } from "../utils/loadProto.js"
// import { interceptor_a, interceptor_b } from "./client.interceptor.js"
import { appendAuthorization } from "./auth.interceptor.js"
import { loggingClientInterceptor } from "./logger.interceptor.js"

function unaryEchoCall(client) {
  return new Promise((resolve, reject) => {
    const requestHeaderMetadata = new grpc.Metadata()
    requestHeaderMetadata.set("timestamp", new Date().toISOString())

    const call = client.unaryEcho(
      { name: "tom" },
      requestHeaderMetadata,
      (error, res) => {
        if (error) {
          // error = {"code":1,"details":"Cancelled on client","metadata":{}}
          console.log(`Received unexpected error ${JSON.stringify(error)}`)
        }
        if (res) {
          console.log(`Received response ${res}`)
        }
        resolve()
      }
    )

    setTimeout(() => {
      console.log(`Client Trigger Cancel`)
      call.cancel()
    }, 2000)

    // response header 接收
    call.on("metadata", (metadata) => {
      const timestamps = metadata.get("timestamp")

      if (timestamps.length > 0) {
        console.log("timestamp from header:")
        for (const [index, value] of timestamps.entries()) {
          console.log(` ${index}. ${value}`)
        }
      } else {
        console.error("timestamp expected but doesn't exist in header")
      }
    })

    // response trailer 接收
    call.on("status", (status) => {
      const timestamps = status.metadata.get("timestamp")

      if (timestamps.length > 0) {
        console.log("timestamp from trailer:")
        for (const [index, value] of timestamps.entries()) {
          console.log(` ${index}. ${value}`)
        }
      } else {
        console.error("timestamp expected but doesn't exist in trailer")
      }
      resolve()
    })
  })
}

function streamingCall(client) {
  return new Promise((resolve, reject) => {
    // request header 发送
    const requestHeaderMetadata = new grpc.Metadata()
    requestHeaderMetadata.set("timestamp", new Date().toISOString())

    const call = client.ServerStreamingEcho()

    let result = ""
    call.on("data", (data) => {
      result += data.value

      if (result === "Hello") {
        console.log(`Client Trigger Cancel`)
        call.cancel()
      }
    })

    call.on("error", (error) => {
      // error =  {"code":1,"details":"Cancelled on client","metadata":{}}
      console.log(`Received unexpected error ${JSON.stringify(error)}`)
    })

    // response header 接收
    call.on("metadata", (metadata) => {
      const timestamps = metadata.get("timestamp")

      if (timestamps.length > 0) {
        console.log("timestamp from header:")
        for (const [index, value] of timestamps.entries()) {
          console.log(` ${index}. ${value}`)
        }
      } else {
        console.error("timestamp expected but doesn't exist in header")
      }
    })

    // response trailer 接收
    call.on("status", (status) => {
      const timestamps = status.metadata.get("timestamp")

      if (timestamps.length > 0) {
        console.log("timestamp from trailer:")
        for (const [index, value] of timestamps.entries()) {
          console.log(` ${index}. ${value}`)
        }
      } else {
        console.error("timestamp expected but doesn't exist in trailer")
      }

      if (status.code === grpc.status.OK) {
        console.log(`Client Received: ${result}`)
        resolve()
      }
    })

    call.on("end", () => {
      console.log(`Received end`)
    })
  })
}

async function main() {
  const PROTO_PATH = resolve(process.cwd(), "./echo.proto")
  const echoProtoDescriptor = loadProto(PROTO_PATH)
  const echoProto = echoProtoDescriptor.echo
  const client = new echoProto.Echo(
    "localhost:50051",
    grpc.credentials.createInsecure(),
    {
      // interceptors: [interceptor_a, interceptor_b],
      interceptors: [appendAuthorization, loggingClientInterceptor],
    }
  )

  await unaryEchoCall(client)
  // console.log("==============================")
  // await streamingCall(client)
}

main()
